package com.jwsoft.manager.core.dao.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.bifang.engine.assistant.core.enums.BoolEnum;
import com.bifang.engine.assistant.core.exception.AppException;
import com.bifang.module.base.common.util.CommonSecureUtil;
import com.jwsoft.manager.common.enums.EduStatusTypeEnum;
import com.jwsoft.manager.common.vo.eduDataTaskDetail.DataTaskDetailOptionVO;
import com.jwsoft.manager.common.vo.eduLivePlace.EduLivePlaceQueryVO;
import com.jwsoft.manager.core.dao.mapper.EduhLivePlaceMapper;
import com.jwsoft.manager.core.dao.mapper.EdutLivePlaceMapper;
import com.jwsoft.manager.core.dao.model.*;
import com.jwsoft.manager.core.dao.mapper.EduLivePlaceMapper;
import com.jwsoft.manager.core.dao.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 服务实现类
 *
 * @author wangtao
 * @since 2022-12-28
 */
@Service
@Slf4j
public class EduLivePlaceServiceImpl extends ServiceImpl<EduLivePlaceMapper, EduLivePlace> implements EduLivePlaceService, TableService {

    @Autowired
    private EduhLivePlaceMapper hLivePlaceMapper;

    @Autowired
    private EdutLivePlaceMapper tLivePlaceMapper;

    @Autowired
    private EduDataTaskDetailService detailService;

    @Autowired
    private TransactionTemplate transactionTemplate;

    private static final String LIVE_PLAVE_TABLE = "edu_live_place";
    //每次处理的数量为1w条数据
    private static final Integer PAGE_SIZE = 10000;


    @Override
    public Integer dataMigration(DataTaskDetailOptionVO optionVO) {
        EduDataTaskDetail taskDetail = detailService.getById(optionVO.getTaskDetailId());
        log.info("调用了EduLivePlaceServiceImpl服务的dataMigration()来进行处理迁移数据");
        //需要根据年度对居住证信息进行数据迁移
        //判断是否还有需要迁移的数据
        Integer count = this.baseMapper.selectCountByYear(optionVO.getYear());
        log.info("edu_live_place迁移" + count + "条数据");
        int totalPages = (count % PAGE_SIZE == 0) ? (count / PAGE_SIZE) : (count / PAGE_SIZE + 1);
        for (int i = 0; i < totalPages; i++) {
            List<EduLivePlace> eduLivePlaces = this.baseMapper.selectByYear(optionVO.getYear(),PAGE_SIZE);
            if (eduLivePlaces.size() > 0) {
                List<EduhLivePlace> hlivePlaces = eduLivePlaces.stream().map(eduLivePlace -> {
                    EduhLivePlace eduhLivePlace = new EduhLivePlace();
                    BeanUtils.copyProperties(eduLivePlace,eduhLivePlace);
                    eduhLivePlace.setTaskDetailId(taskDetail.getTaskDetailId());
                    //数据是否已加密，初始状态未加密
                    eduhLivePlace.setEncryptFlag(BoolEnum.FALSE.getType());
                    eduhLivePlace.setEncryptStatus(EduStatusTypeEnum.dcl.getType());
                    eduhLivePlace.setCleanFlag(BoolEnum.FALSE.getType());
                    return eduhLivePlace;
                }).collect(Collectors.toList());
                try {
                    this.performDataMigration(hlivePlaces, eduLivePlaces.size(),optionVO);
                } catch (Exception e) {
                    log.error("edu_live_place迁移数据发生异常");
                    throw new RuntimeException("EduLivePlaceServiceImpl:" + e);
                }
            }
        }
        //返回迁移成功的数量
        return count;
    }

    /**
     * 具体的迁移数据方法
     * 做两件事，同一个事务内
     * 1.将数据从在线表迁移到历史表
     * 2.将在线表的数据进行删除
     * @param hlivePlaces
     * @param count
     * @param optionVO
     */
    public Integer performDataMigration(List<EduhLivePlace> hlivePlaces, Integer count, DataTaskDetailOptionVO optionVO) {
        Integer result = transactionTemplate.execute(new TransactionCallback<Integer>() {
            @Override
            public Integer doInTransaction(TransactionStatus status) {
                try {
                    //1.数据迁移到历史表
                    int saveHCount = hLivePlaceMapper.saveBatch(hlivePlaces);
                    if (saveHCount != count) {
                        throw new RuntimeException("数据迁移到历史表失败");
                    }
                    //2.数据销毁
                    EduDataTaskDetail taskDetail = detailService.getById(optionVO.getTaskDetailId());
                    if (ObjectUtils.isEmpty(taskDetail)) {
                        throw new AppException("任务数据不存在，请检查数据是否有误");
                    }
                    Integer deleteCount = baseMapper.deleteByTaskHistory(taskDetail.getTaskDetailId());
                    if (!count.equals(deleteCount)) {
                        throw new RuntimeException("数据删除失败");
                    }
                    log.info("edu_live_place数据销毁成功！销毁数量：" + count);
                    return count;
                } catch (Exception e) {
                    status.setRollbackOnly();
                    throw e;
                }
            }
        });
        //返回处理的结果数量
        return result;
    }

    @Override
    public void dataEncryption(DataTaskDetailOptionVO optionVO) {
        EduDataTaskDetail taskDetail = detailService.getById(optionVO.getTaskDetailId());
        log.info("调用了EduLivePlaceServiceImpl服务的dataEncryption()来进行处理数据加密");
        Integer count = 0;
        //当前任务加密数量为0 表示是首次进行数据加密
        if (taskDetail.getEncryptCount() == 0) {
            //查询需要处理加密的数量进行设置
            count = this.baseMapper.selectEncryptionCountByYear(optionVO.getYear(), optionVO.getTaskDetailId());
            taskDetail.setEncryptCount(count);
        }
        Boolean errorFlag = false;
        Integer errorCount = 0;
        int totalPages = (count % PAGE_SIZE == 0) ? (count / PAGE_SIZE) : (count / PAGE_SIZE + 1);
        for (int i = 0; i < totalPages; i++) {
            //查询出需要加密的数据
            List<EduhLivePlace> hLivePlaces =
                    this.baseMapper.selectEncryptionByYear
                            (optionVO.getYear(), optionVO.getTaskDetailId(),PAGE_SIZE);
            for (EduhLivePlace hLivePlace : hLivePlaces) {
                //加密
                try {
                    this.encrypt(hLivePlace);
                    hLivePlace.setEncryptTime(new Date());
                    hLivePlace.setEncryptStatus(EduStatusTypeEnum.success.getType());
                    hLivePlace.setEncryptRemarks("加密成功");
                    hLivePlace.setEncryptFlag(BoolEnum.TRUE.getType());
                    hLivePlaceMapper.updateById(hLivePlace);
                } catch (Exception e) {
                    //解密
                    this.decrypt(hLivePlace);
                    hLivePlace.setEncryptTime(new Date());
                    hLivePlace.setEncryptStatus(EduStatusTypeEnum.error.getType());
                    hLivePlace.setEncryptFlag(BoolEnum.FALSE.getType());
                    hLivePlace.setEncryptRemarks("加密失败" + e.getMessage());
                    hLivePlaceMapper.updateById(hLivePlace);
                    errorFlag = true;
                    errorCount++;
                    throw new AppException(e);
                }
            }
        }
        if (!errorFlag) {
            //无异常，返回任务状态
            taskDetail.setEncryptStatus(EduStatusTypeEnum.success.getType());
            taskDetail.setEncryptRemarks("加密成功");
            taskDetail.setEncryptTime(new Date());
        } else {
            taskDetail.setEncryptStatus(EduStatusTypeEnum.error.getType());
            taskDetail.setEncryptTime(new Date());
            taskDetail.setEncryptRemarks(taskDetail.getHandleTable()
                    +"加密失败,加密出错的数据：" + errorCount);
        }
        detailService.updateById(taskDetail);
    }

    /**
     * 历史数据加密
     * @param eduhLivePlace
     */
    @Override
    public void encrypt(EduhLivePlace eduhLivePlace) {
        if (StringUtils.isNotBlank(eduhLivePlace.getSfzh())) {
            eduhLivePlace.setSfzh(CommonSecureUtil.sm4Encrypt(eduhLivePlace.getSfzh()));
        }
        if (StringUtils.isNotBlank(eduhLivePlace.getXm())) {
            eduhLivePlace.setXm(CommonSecureUtil.sm4Encrypt(eduhLivePlace.getXm()));
        }
        if (StringUtils.isNotBlank(eduhLivePlace.getJzdz())) {
            eduhLivePlace.setJzdz(CommonSecureUtil.sm4Encrypt(eduhLivePlace.getJzdz()));
        }
    }

    /**
     * 历史数据解密
     * @param eduhLivePlace
     */
    @Override
    public void decrypt(EduhLivePlace eduhLivePlace) {
        if (StringUtils.isNotBlank(eduhLivePlace.getSfzh())) {
            eduhLivePlace.setSfzh(CommonSecureUtil.sm4Decrypt(eduhLivePlace.getSfzh()));
        }
        if (StringUtils.isNotBlank(eduhLivePlace.getXm())) {
            eduhLivePlace.setXm(CommonSecureUtil.sm4Decrypt(eduhLivePlace.getXm()));
        }
        if (StringUtils.isNotBlank(eduhLivePlace.getJzdz())) {
            eduhLivePlace.setJzdz(CommonSecureUtil.sm4Decrypt(eduhLivePlace.getJzdz()));
        }
    }

    /**
     * 查询条件加密
     * @param vo
     */
    @Override
    public void queryEncrypt(EduLivePlaceQueryVO vo) {
        if (StringUtils.isNotBlank(vo.getSfzh())) {
            vo.setSfzh(CommonSecureUtil.sm4Encrypt(vo.getSfzh()));
        }
        if (StringUtils.isNotBlank(vo.getXm())) {
            vo.setXm(CommonSecureUtil.sm4Encrypt(vo.getXm()));
        }
        if (StringUtils.isNotBlank(vo.getJzdz())) {
            vo.setJzdz(CommonSecureUtil.sm4Encrypt(vo.getJzdz()));
        }
    }

    /**
     * 历史数据销毁
     * 居住证销毁规则
     * 根据报名表中（父母，孩子）身份证去保留
     * @return
     */
    @Override
    public Integer dataDestruction(DataTaskDetailOptionVO optionVO) {
        EduDataTaskDetail taskDetail = detailService.getById(optionVO.getTaskDetailId());
        log.info("调用了EduLivePlaceServiceImpl服务的dataDestruction()来进行处理数据销毁");
        //判断居住证信息是否进行了迁移
        Boolean queryHistory =
                detailService.verifyQueryHistory(optionVO.getYear(), LIVE_PLAVE_TABLE);
        List<EduhLivePlace> hLivePlaces = new ArrayList<>();
        if (queryHistory){
            //查询历史报名数据,查出的数据无需进行解密，原则上加密了才能进行迁移
            hLivePlaces = this.baseMapper
                    .queryCleanHistoryEnrollWithLivePlace (taskDetail.getYear(),taskDetail.getTaskDetailId());
        }else{
            //查询在线表数据
            List<String> idcards = this.baseMapper.queryEnrollIdcardByYear(taskDetail.getYear());
            //对身份证数据进行加密
            idcards = idcards.stream().map(idcard ->{
                idcard = CommonSecureUtil.sm4Encrypt(idcard);
                return idcard;
            }).collect(Collectors.toList());
            hLivePlaces = this.baseMapper
                    .queryCleanLivePlaceByIdcards(idcards);
        }
        Integer cleanCount = hLivePlaces.size();
        if (cleanCount != 0){
            try {
                this.preformDataClean(hLivePlaces,cleanCount);
            } catch (Exception e) {
                log.error("eduh_live_place数据清洗发生异常");
                throw new RuntimeException("EduLivePlaceServiceImpl:" + e);
            }
        }
        return 0;
    }

    private void preformDataClean(List<EduhLivePlace> hLivePlaces, Integer cleanCount) {
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                try {
                    List<EdutLivePlace> tLivePlaces = hLivePlaces.stream().map(eduhLivePlace -> {
                        EdutLivePlace tLivePlace = new EdutLivePlace();
                        BeanUtils.copyProperties(eduhLivePlace, tLivePlace);
                        tLivePlace.setCleanFlag(BoolEnum.TRUE.getType());
                        return tLivePlace;
                    }).collect(Collectors.toList());
                    tLivePlaceMapper.saveBatch(tLivePlaces);
                    //根据id进行删除历史表中的数据
                    Integer count = 0;
                    for (EduhLivePlace hLivePlace : hLivePlaces) {
                        count ++;
                        hLivePlaceMapper.deleteHistoryById(hLivePlace.getLivePlaceId());
                    }
                    if (count != cleanCount){
                        throw new AppException("要清洗的数据为："+cleanCount+",清洗的数据为："+count+"数据量不一致，请检查后重试！");
                    }
                } catch (Exception e) {
                    status.setRollbackOnly();
                    throw e;
                }
            }
        });
    }


    /**
     * 临时表数据销毁
     */
    @Override
    public void tempDataDestruction() {
        System.out.println("空闲数据销毁");
    }

    /**
     * 数据解密恢复到临时表
     * @param optionVO
     */
    @Override
    public void dataDecrypt(DataTaskDetailOptionVO optionVO) {
        Integer count = Math.toIntExact(hLivePlaceMapper.selectCount(new QueryWrapper<EduhLivePlace>().lambda().eq(EduhLivePlace::getTaskDetailId, optionVO.getTaskDetailId())));
        int totalPages = (count % PAGE_SIZE == 0) ? (count / PAGE_SIZE) : (count / PAGE_SIZE + 1);
        int currentPage = 0;
        for (int i = 0; i < totalPages; i++) {
            //将历史表数据查询出来
            List<EduhLivePlace> hLivePlaceList
                    = hLivePlaceMapper.selectByTaskDetailId(optionVO.getTaskDetailId(),currentPage,PAGE_SIZE);
            //遍历每条数据，根据encryptFlag来决定进行解密
            List<EdutLivePlace> tLivePlaces = hLivePlaceList.stream().map(hLivePlace -> {
                if (BoolEnum.TRUE.getType().equalsIgnoreCase(hLivePlace.getEncryptFlag())) {
                    //需要进行解密
                    this.decrypt(hLivePlace);
                }
                EdutLivePlace tLivePlace = new EdutLivePlace();
                BeanUtils.copyProperties(hLivePlace,tLivePlace);
                return tLivePlace;
            }).collect(Collectors.toList());
            //将恢复的数据插入到临时表中
            tLivePlaceMapper.saveBatch(tLivePlaces);
            currentPage ++;
        }

    }


}
